๐ ๊ณผ์  ์ค๋ช
์ด๋ฒ ๊ณผ์ ๋ ์ด๋ฒ ๊ธฐ๊ฐ์ ์ฐธ๊ฐํ ๊ธฐ์ ์ ๊ณผ์ ๋ ์๋์ง๋ง ์ด์  ๊ธฐ์์์ ์ฃผ์ด์ก๋ ๊ณผ์ ๋ก, ๋ฉํ ๋๊ป์ ์ข์ ๊ณผ์ ๋ผ ์๊ฐํ์ ์ ๋ฃ์ผ์ จ๋ค๊ณ ํ๋ค. ๊ธฐ์ ์ ๊ด๊ณ ํ์ฌ๋ก ๊ด๊ณ ์ ๋ง์ผํ ๊ณผ ๊ด๋ จ๋ ๋ฐ์ดํฐ๋ค์ ๋ณด์ฌ ์ฃผ๋ ๋์๋ณด๋์ ๊ด๋ฆฌ ํ์ด์ง๋ฅผ ๋ง๋๋ ๊ณผ์ ์๋ค. ๋์ ์ฒ์ ๋ณด๋ ์ฉ์ด๋ค๊ณผ ๋๋ฌด ๋ํ ์ผ ํ๊ฒ ๊ตฌ์ฑ๋์ด์๋ ํผ๊ทธ๋ง ํ์ด์ง ๋๋ฌธ์ ์ฌํ ๊น์ง ๊ณผ์ ๋ค ์ค์์ ๊ฐ์ฅ ํ๋ ๊ณผ์ ๊ฐ ๋์๋ค...
์ ๋ฒ๊ณผ ๋์ผํ๊ฒ Typescript์ Context API, useReducer๋ฅผ ํ์ฉํด ์ํ ๊ด๋ฆฌ๋ฅผ ํ๋ค. ๊ทธ๋ํ๋ฅผ ์ํด์๋ APEXCHART ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ๋ ์ง ๋ณ๊ฒฝ์ ์ํด์๋ reat-picker ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด ์งํํ๋ค. ์ด๋ฒ์ ๊ณผ์ ๋ฅผ ํ๋ฉด์ ์๋ํด๋ณด๊ณ ์ถ์๋ ๊ฒ์ ๋ ๊ฐ์ง๋ก, ์์ ์ ํตํด ๋ฐฐ์ ๋ ๊ด์ฌ์ฌ ๋ถ๋ฆฌ์ redux๋ฅผ ์ด์ฉํ ์ ์ญ ์ํ ๊ด๋ฆฌ์๋ค. ํ์ง๋ง ๊ธฐ๋ฅ ๊ตฌํ์๋ ๋๋ฌด ๋ง์ ์๊ฐ์ด ๋ค์ด, redux๋ฅผ ์๋ํ ์๊ฐ์ด ์์ด ๋น ๋ฅด๊ฒ ContextAPI๋ฅผ ์ด์ฉํด ์ ์ญ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ค.
๐ ๊ด์ฌ์ฌ ๋ถ๋ฆฌ
๊ด์ฌ์ฌ ๋ถ๋ฆฌ๋ ์ข์ ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ํ ๊ธฐ์ค์ด ๋์ด ์ค๋ค. KISS (Keep it simple stupid)๋ผ๊ณ ๋ถ๋ฆฌ๋ ์์น์ ํ๋์ ๋ชจ๋์ด ํ๋์ ๊ธฐ๋ฅ๋ง์ ํ๊ฒํ๋ผ๋ ๋ป์ด๋ค. ์ฒ์์ ์๊ฐํ์ ๋ ํ๋์ ๋ชจ๋์ด ์ฌ๋ฌ๊ฐ์ง ๊ธฐ๋ฅ์ ํ๊ฒ ๋๋ฉด ๋ ์ข์ง ์์๊น ๋ผ๋ ์๊ฐ์ ํ์ง๋ง, ๋ฌธ์ ๊ฐ ์๊ฒผ์ ๋ ์ฌ๋ฌ ๊ธฐ๋ฅ์ด ์์ผ ์๋ค๋ฉด ํด๋น ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ค ๋ค๋ฅธ ๊ธฐ๋ฅ์ด ์ํฅ์ ๋ฐ๋ ์ผ์ด ์๊ธฐ๊ฒ ๋๋ค. ์ด๋ฌํ ์ํ๋ฅผ ํํ "์คํ๊ฒํฐ ์ฝ๋"๋ผ๊ณ ๋ถ๋ฆฐ๋ค.
์ฌ์ค ํจ์๋ฅผ ๋ฐฐ์ฐ๋ฉด์ ํ๋์ ๊ธฐ๋ฅ๋ง ํ๊ฒ ํด์ผ ํ๋ค๋ ์์น์ ๋๋ฌด ๋ง์ด ๋ค์ด์์ง๋ง, ๋์ค์ ๋ด๊ฐ ํ๋ ํ๋ก์ ํธ์ ์ฝ๋๋ฅผ ๋์๋ณด๋ฉด ๋์ ํ ์๋ ์ ์์ด ์์ผ์๋ ๊ฒ์ ๋ณด๊ฒ ๋๋ค. ์ด๋ฌํ ํ๋์ ๋ชจ๋์ด ํ๋์ ๊ธฐ๋ฅ๋ง ํ๊ธฐ ์ํด์๋ ์๋ก ๋ค๋ฅธ ๊ด์ฌ์ฌ๋ฅผ ํ๋์ ๋์ง ์๋ ๊ด์ฌ์ฌ ๋ถ๋ฆฌ๊ฐ ํ์ํ๋ค. ๋ด๊ฐ ์ข์ํ๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ ๋ฉํฐ ํจ๋ฌ๋ค์ ์ธ์ด์ด๊ธฐ ๋๋ฌธ์, ํจ์ํ ํ๋ก๊ทธ๋๋ฐ๊ณผ ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ ๋ ๊ฐ์ง ๋ชจ๋ ๊ฐ๋ฅํด, class๋ก ๋ชจ๋์ ๋๋๊ณ , ํ์ํ ๊ณณ์ ์ฌ์ฉํ ์ ์๊ฒ ์ ๋ฌ (Dependency Injection)ํ๋ฉด ์ฌ์ฉํ๋ ๊ณณ์์๋ ์ด๋ป๊ฒ ๊ตฌ์ฑ๋์ด์๋์ง ์์ธํ ์์ง ๋ชปํด๋ ์ฌ์ฉํ ์ ์๋ ์ถ์ํ๊ฐ ๋ ๋ชจ๋๋ค๋ก ์ฐ๊ฒฐํด ๋๊ฐ ์ ์๋ค.
์ด์ ์ class๋ฅผ ์ฌ์ฉํ ๋ ํ๋์ ๊ธฐ๋ฅ์ ํ๋ ๊ด๋ จ๋ ๊ฒ๋ค์ ๋ชจ์๋์๋ ๊ธฐ์ค์ผ๋ก index.tsx์์ instance๋ฅผ ๋ง๋ค์ด ์ ๋ฌํ๋ ๋ฐฉ์์ ์๊ณ ๋ ์์์ง๋ง ์ฌ์ฉํ๋ ๊ณณ๊น์ง ๊ณ์ํด์ prop์ผ๋ก ์ ๋ฌํ๋ ๋ฐฉ์์ ์ด์ฉํ๋ค. ์ด๋ฌํ ๋ฐฉ์์ ๋๊ฐ์ด prop-drilling์ด ๋ฐ์ํ๊ฒ ๋๊ณ ์คํ๋ ค ๋ ๋ณต์กํ๊ฒ ๋๋๋ฐ, ์ด๋ ์ฌ์ฉํ ์ ์๋ ๊ฒ ์ด์ ์ ๋ฐฐ์ ๋ context API์๋ค.
๊ทธ๋ฆฌ๊ณ Typescript๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ณด๋ค ๊ฐ๋ ฅํ ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ๊ธฐ๋ฅ๋ค์ ๋ด๊ณ ์๋ค. Typescript์ interface๋ ์ฐ๋ฆฌ๊ฐ ๋ง๋ค๊ณ ์ ํ๋ ๋ชจ๋์ ๋ช ์ธ์๋ก ์ด๋ ํ ์ํ์ ํ๋๋ค์ ํ๋ ๋ชจ๋์ธ์ง ์ ํ๊ณ , ๊ทธ๊ฒ์ implementsํ๋ class๋ฅผ ๋ง๋ค ์ ์๋ค.
๐ Interface
์ด๋ฒ ๊ณผ์ ์์ ๋ง๋ค์๋ class๋ ๋๊ฐ์ง ๊ด๊ณ ๋ฐ์ดํฐ๋ฅผ api๋ก ๋ถ๋ฌ์ค๋ ๋ชจ๋์ด ํ์ํ๋ค. ๊ทธ๋์ interface๋ ๋ค์๊ณผ ๊ฐ์ ๋ ๊ฐ์ง ํจ์๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
type GetAdListResponse = {
  ads: AdType[]
  counts: number
}
type GetTrendResponse = {
  report: {
    daily: TrendType[]
  }
}
interface AdService {
  getAdList: () => Promise<GetAdListResponse>
  getTrend: () => Promise<GetTrendResponse>
}API ํต์ ์ ์ํ class์ด๋ฏ๋ก ๊ฐ ๋ฉ์๋๋ ํต์ ๊ฒฐ๊ณผ์ธ promise๋ฅผ ๋ฐํํ๊ณ promise ๋ด๋ถ์ ๋ฐ์ดํฐ ํ์ ์ ์ ํด์ฃผ๋ฉด interface๋ฅผ ์์ฑํ ์ ์๋ค.
๐ Class
์ฐ๋ฆฌ๊ฐ ์ ์ํ interface๋ฅผ ๊ตฌํํ๋ class์ธ AdserviceImpl๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ๋ง๋ค ์ ์๋ค.
import { AxiosError, AxiosInstance } from "axios"
import {
  AdService,
  GetAdListResponse,
  GetTrendResponse,
} from "models/interface"
import HTTPError from "../network/httpError"
const AD_LIST_URL = "/ad-list-data-set.json"
const AD_TREND_URL = "/trend-data-set.json"
class AdServiceImpl implements AdService {
  constructor(private axiosInstance: AxiosInstance) {}
  getAdList = async () => {
    try {
      const { data } = await this.axiosInstance.get<GetAdListResponse>(
        AD_LIST_URL
      )
      return data
    } catch (error) {
      const { response } = error as unknown as AxiosError
      if (response) {
        throw new HTTPError(response?.status, response?.statusText)
      }
      throw new Error("Unknown Error")
    }
  }
  getTrend = async () => {
    try {
      const { data } = await this.axiosInstance.get<GetTrendResponse>(
        AD_TREND_URL
      )
      return data
    } catch (error) {
      const { response } = error as unknown as AxiosError
      if (response) {
        throw new HTTPError(response?.status, response?.statusText)
      }
      throw new Error("Unknown Error")
    }
  }
}
export default AdServiceImpl์ด์ ๋ถํฐ ํญ์ ์ฌ์ฉํด์ค๋ HTTPError class๋ ์ํ๋ ์๋ฌ๋ฉ์์ง๋ฅผ ์ปค์คํ ํ ์ ์๊ฒ ํ๋ ์ ๋๋ก ์ฌ์ฉํ์ง๋ง ์๋ฌ๊ฐ ๋ค์ํด์ง๊ณ ๋ณต์กํด์ง๋ฉด class์ ๋ด์ฉ๋ง ์ถ๊ฐํ๋ฉด ๋๋๊น ํจ์ฌ ์ ์ง ๋ณด์์ ์ ์ฉํ ๊ฒ์ด๋ ์์์ ํ ์ ์๋ค.
export default class HTTPError extends Error {
  constructor(private statusCode: number, public message: string) {
    super(message)
  }
  get errorMessage() {
    switch (this.statusCode) {
      case 404:
        this.message = "์๋ชป๋ ์์ฒญ์
๋๋ค. url์ ํ์ธํด์ฃผ์ธ์"
        break
      default:
        throw new Error("Unknown Error")
    }
    return this.message
  }
}๐ Dependency Injection
์์ ๋ง๋ AdService๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ instance๋ฅผ ๋ง๋ค๊ณ instance๋ฅผ context API๋ก ์ ๋ฌํด์ฃผ๋ฉด ํ์ํ ๊ณณ์์ ํธํ๊ฒ ์ฌ์ฉํ ์ ์๋ค. typescript๋ก contextAPI๋ก instance๋ฅผ ์ ๋ฌํ ๋ ์ด๋ป๊ฒ type์ ์ ๋ฌํด์ผ ํ ์ง ํด๊ฒฐํ๋ ์์ค์, ์ฐ๋ฆฌ๊ฐ ์ ์ํ interface๋ฅผ ๊ทธ๋๋ก ์ ๋ฌํด์ฃผ๋ฉด type์ ๊ฐ๋จํ๊ฒ ์ ํด์ค ์ ์๋ค๋ ์ ์ ์๊ฒ ๋์๋ค. interface๋ฅผ ๊ธฐ์ค์ผ๋ก class๋ฅผ ๋ง๋๋ ์์กด์ฑ ์ญ์  ์์น์ ์ดํดํ๋ ๊ฒฝํ์ด์๋ค.
[adService์ type์ interface๋ก ์ ๋ฌํด์ฃผ๊ธฐ ์ ์ ์๋ฌ]
์ฌ๊ธฐ์ ์กฐ๊ธ ์ฃผ์ํ ๋ถ๋ถ์ ์ ๋ฌํ๋ฉด์ instance๊ฐ this๋ฅผ ์์ด๋ฒ๋ฆฐ๋ค๋ ์ ์ด๋ค. ๊ทธ๋์ bind๋ก adService๋ฅผ binding์ ํด์ฃผ๊ฑฐ๋, method ์์ฒด๋ฅผ arrow function์ผ๋ก ๋ฐ๊พธ๊ฒ ๋๋ฉด, this binding ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
//index.tsx
const BASE_URL = process.env.REACT_APP_BASE_URL || ""
const axiosInstance = createAxiosClient(BASE_URL)
const adService = new AdService(axiosInstance)
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
root.render(
  <React.StrictMode>
    <AdServiceProvider adService={adService}>..</AdServiceProvider>
  </React.StrictMode>
)
//AdServiceContext.tsx
import { AdService } from "models/interface"
import { createContext, useMemo, useContext } from "react"
const AdServiceContext = createContext<AdService | null>(null)
export const useAds = () => useContext(AdServiceContext)
export const AdServiceProvider = ({
  children,
  adService,
}: {
  children: React.ReactNode
  adService: AdService //interface๋ก ๋ฐ๋ก type์ ํด์ค ์ ์์ด
}) => {
  const { getAdList, getTrend } = adService
  const value = useMemo(() => {
    return { getAdList, getTrend }
  }, [getAdList, getTrend])
  return (
    <AdServiceContext.Provider value={value}>
      {children}
    </AdServiceContext.Provider>
  )
}๐ React Query๋ฅผ ์ด์ฉํ Refactoring
๊ธฐ๋ฅ์ ์ฐ์ ์ผ๋ก ์ฝ๋๋ฅผ ์์ฑํ๋ค ๋ณด๋ ๋๋ฌด ๋น์ทํ ์ฝ๋๊ฐ ๋ ๋ฒ์ด๋ ์ฌ์ฉ๋์๋๋ฐ, ์ฝ๋ ์์ด ๋๋ฌด ๋ง์ ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง๋ ๋ฌธ์ ๋ฅผ ๊ฐ์ง๊ณ ์์๋ค.
const getAdList = useCallback(async () => {
    listDispatch({ type: DataActionEnum.SET_IS_LOADING, isLoading: true });
     try {
      const response = _await_ adService?.getAdList();
      listDispatch({
        type: DataActionEnum.SET_DATA,
        data: response?.ads || [],
      });
    } catch (e) {
      console.error(e);
    } finally {
      listDispatch({ type: DataActionEnum.SET_IS_LOADING, isLoading: false });
    }
  }, [adService, listDispatch]);
const getAdTrend = useCallback(async () => {
    trendDispatch({ type: DataActionEnum.SET_IS_LOADING, isLoading: true });
    try {
      const response = _await_ adService?.getTrend();
      trendDispatch({
        type: DataActionEnum.SET_DATA,
        data: response?.report.daily || [],
      });
    } catch (e) {
      console.error(e);
    } finally {
      trendDispatch({ type: DataActionEnum.SET_IS_LOADING, isLoading: false });
    }
  }, [adService, trendDispatch]);dispatchํจ์์ action๋ด์ฉ๋ง ๋ฐ๋๋ ๋ ๊ฐ์ง ํจ์ ๋ด์ฉ์ ๋ณด๋ฉด์ ํ๋์ ํจ์๋ก ๋ง๋ค์ด์ ์ ๋ฌํ ๊น๋ ์๊ฐํ์ง๋ง Type๊ณผ ๊ด๋ จํด์ ๋๋ฌด ๋ณต์กํด์ง๋ ๋ฌธ์ ๋ฅผ ๊ฐ์ง๊ณ ์์๋ค. ์ฝ๋์ ๊ฐ๊ฒฐํ์ ๋ ๊ฐ์ง ๋ถ๋ฆฌ๋ ํจ์๋ฅผ ๊ฐ์ง๋ ๊ฒ ๋ ์ข์ ๊ฒ ๊ฐ์ React Query๋ฅผ ์ฌ์ฉํ๋ค.
React Query
React Query๋ ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๊ณ , ๋ฐ์์จ ๋ฐ์ดํฐ๋ฅผ caching, retry ๋ฑ ๋น๋๊ธฐ์ ํ์ํ ๋ค์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํด ์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค. React Query๋ ์ดํ์ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฐ๋ํ๋ค๋ฉด ์ํ๋ ์ํ๋ฅผ ๋ณด๊ดํ๊ณ ๋ณ๊ฒฝํ๋ ์ญํ ๋ง, React Query๋ก๋ ์๋ฒ์์ ๋ฐ์์จ ๋ฐ์ดํฐ๋ง์ ๊ด๋ฆฌํ๋ ์ญํ ๋ง ๋ถ๋ฆฌํด์ ์ฌ์ฉํ ์ ์์ ๊ฒ ๊ฐ์ ๊ณต๋ถํ๊ณ ์ ์ฉํด๋ณด์๋ค.
์ ์ํฉ์ ๋ ๊ฐ์ง API ํจ์๋ก ํธ์ถ์ ํ๋ ์ํฉ์ด๊ณ ๊ฐ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ํ๋ก ์ ๋ฌํด์ค์ผ ํ๋ ์ํฉ์ด์๋ค. (React query๊ฐ ๋์๊ธฐ ๋ฑ ์ข์ ์ํฉ์ด๋ค)
์ด๋ฅผ ๋ฐ์์จ ๊ฒฐ๊ณผ๋ค๋ง ๋ฝ์์ ์ํ๋ฅผ ์ ๋ฌํ๋, ํจ์ฌ ์ฝ๋๊ฐ ๊ฐ๋จํด์ง๊ณ ๊ตฌ๋ถ์ด ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
const { isLoading, data: trendData } = useQuery(
  ["trend"],
  () => adService?.getTrend(),
  {
    staleTime: 1000 * 60 * 60,
    cacheTime: 1000 * 60 * 60,
  }
)
const { data: listData } = useQuery(["adList"], () => adService?.getAdList(), {
  staleTime: 1000 * 60 * 60,
  cacheTime: 1000 * 60 * 60,
})
useEffect(() => {
  trendDispatch({
    type: DataActionEnum.SET_DATA,
    data: trendData?.report.daily || [],
  })
  trendDispatch({ type: DataActionEnum.SET_IS_LOADING, isLoading })
}, [trendData, isLoading])
useEffect(() => {
  listDispatch({
    type: DataActionEnum.SET_DATA,
    data: listData?.ads || [],
  })
}, [listData])๐ Typescript Error
์ญ์ Typescript๋ ์์ง ์ด๋ ต๋ค... ๋ง์ฃผํ๋ ์๋ฌ๋ค์ ๊ธฐ๋กํด ์ดํ์ ๊น๋จน์ ๋ด๊ฐ ์ฐธ๊ณ ํ๋ คํ๋ค.
Object Key Type
์ ๋ฒ ๊ณผ์ ์์ Detail ํ์ด์ง๋ฅผ ๊ตฌ์ฑํ ๋ api๋ก ๋ฐ์ ๋ฐ์ดํฐ ์ค์์ param๊ฐ๊ณผ ๊ฐ์ id๋ฅผ ๊ฐ๋ ๋ฐ์ดํฐ๋ฅผ ์ฐพ์์ ๊ฐ์ ธ์๋ค. ์ด๋ ๊ฒ ํ ๋ ๋ง์ฝ์ ๋ฐ์ดํฐ๊ฐ ์ปค์ง๋ค๋ฉด ์ฐพ๋๋ฐ ํจ์ฌ ์ค๋ ์๊ฐ์ด ๊ฑธ๋ฆฌ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค (๋ฐฐ์ด์์ ์ฐพ๊ธฐ๋ O(n)). ๊ทธ๋์ Object๋ก ์๋ฃ๊ตฌ์กฐ๋ฅผ ๋ฐ๊พธ๋ ค ํ์๋๋ฐ Type์ ์ด๋ป๊ฒ ์ค์ ํ ์ง ๋ชฐ๋ผ ํฌ๊ธฐํ๋ ๊ฒฝํ์ด ์๋ค.
์ด๋ฒ์๋ ๋ฐ์ดํฐ๋ฅผ ๊ณ์ฐํ๋ฉด์ Object.keys() ๋ฉ์๋๋ฅผ ์ด์ฉํ๋๋ฐ, ๋์ดํ๋ ค๋ฉด index์ type์ ๊ฒฐ์ ํด์ค์ผ ํ๋ค.
export type ResultType = {
  [index: string]: number
}
const calculateData = (data: TrendType[]) => {
  const result: ResultType = {
    imp: 0,
    click: 0,
    cost: 0,
    conv: 0,
    convValue: 0,
    ctr: 0,
    cvr: 0,
    cpc: 0,
    cpa: 0,
    roas: 0,
  }
  data.forEach(item => {
    Object.keys(item).forEach(key => {
      if (key in result) {
        result[key] += Number(item[key])
      }
    })
  })
  return result
}
export default calculateData๋ง์ฝ ์ ๋ฒ ๊ณผ์ ์์ ํด๊ฒฐ ๋ชปํ๋ Object์ key๋ก ๋ฐ์ดํฐ์ id๋ฅผ ์ฌ์ฉํ๊ณ ๋ฐ์ดํฐ๋ฅผ value๋ก ํ ์๋ฃ๊ตฌ์กฐ์ type ๊ฒฝ์ฐ๋ ๋ค์๊ณผ ๊ฐ์ด ์ ์ฉํ ์ ์๋ค.
type Type = {
  [index: string]: { data: string }
}
const obj: Type = {
  "123123": { data: "hi" },
}๐ฅ์์ฌ์ ๋ ์ 
์ด๋ฒ ๊ณผ์ ๋ ๋๋ฌด ๋ํ ์ผํ UI๋ค๊ณผ selector๋ฅผ ์ด์ฉํด ๋ฐ์ ๋ฐ์ดํฐ๋ค์ ํํฐ ํด์ผ ํ๋ ๋ถ๋ถ๋ค์ด ๋ง์, ์์ ํ ๊ตฌํํ์ง ๋ชปํ๋ค. ํํฐ๋ง ๋ก์ง์ ๋ง์ด ๊ตฌํํ๋ค ์๊ฐ์ด ์์ด ๊ทธ๋ํ์ ํ์๋ค๋ ์ ๊ฒฝ ์ฐ์ง ๋ชปํ๊ณ , adList ๋ฐ์ดํฐ๋ก ์์ ํ๊ธฐ ๋ถ๋ถ๋ ๊ตฌํํ์ง ๋ชปํ๋ค. ์์ง ๋๋ฌด ๋ง์ด ๋ถ์กฑํ๋ค๋ ๊ฒ์ ๋ง์ด ๋๋๋ค. ์ฝ๋ฉ์ ํ๋ฉด์ ์ ๋ฒ์ ํ๋ ์ฝ๋๋ฅผ ๋ณต์ฌํด ์์ ํด์ ์ฌ์ฉํ๋ค ๋ณด๋, "์ ๋ง ๋ด๊ฐ ์ด ์ฝ๋๋ค์ ์ ๋๋ก ์ดํดํ๊ณ ์๋ ๊ฑธ๊น"๋ผ๋ ์๊ฐ๋ ๋ค๊ณ , ๋ถ์กฑํจ์ ์ข์ ํ๊ธฐ๋ ๋ง์ด ํ๋ค.
๊ทธ๋๋ ๋งค๋ฒ ๊ณผ์ ๋ฅผ ํ๋ฉด์ ๋ด๊ฐ ๊ฐ์ง ์ฅ์ ์, ํ๋ก์ ํธ ๋ด์ ๋ฌธ์ ์ ์ ์ ์ฐพ๋๋ค๋ ์ ๊ณผ ๋ฐฐ์ด ๊ฒ์ ์ ์ฉํ ์ ์๋ ๋ฅ๋ ฅ์ด๋ผ๊ณ ์๊ฐํ๋ค. ๋ด ํ๋ก์ ํธ์์ ๋ถ์กฑํ ์ ๋ค์ ๊ธฐ๋กํด์ ์ต๋ํ ์ฑ์ ๊ณ , ๋ฉํ ๋์ด ๋ง์ํด ์ฃผ์ จ๋ ๋ถ๋ถ๋ค์ ๋ด์์ ์ฝ๋ฉํ๋ค ๋ณด๋ ์ด์ ๊ณผ๋ ๋ค๋ฅธ ์์ผ์ ๋ค๋ฅธ ์์ค์ผ๋ก ์ฝ๋ฉํ๊ณ ์๋ค๋ ์๊ฐ์ ํ๋ค.
์ข์ ํ๊ณ ํ๋ค์์ง๋ง ๊ฑฐ๊ธฐ์ ๋ฉ์ถ์ง ๋ง๊ณ ์ด๋ฒ ๋ถ์กฑํ ๋ถ๋ถ๋ค์ ๋ฐ๊ฑฐ๋ฆ์ผ๋ก ๋ค์์ผ๋ก ๋์๊ฐ์ผ๊ฒ ๋ค.